package jeconbond.automata.behaviour.antstrat;

import jeconbond.automata.INode;
import jeconbond.automata.IOutcome;
import jeconbond.automata.behaviour.IWalkStrategy;
import jeconbond.economic.agent.AutomataAgent;
import jeconbond.economic.agent.BaseEconProdDecoratod;
import jeconbond.economic.market.strategy.IProcessDealStrategy;
import jeconbond.economic.market.strategy.ObserveCostsProfitMerchantDecorator;
import jeconbond.economic.market.strategy.ProductNecessityMerchant;
import jeconbond.economic.production.IResourceNecessityInformer;
import jeconbond.economic.systems.market.IMarketResourceRedestributionSystem;
import jeconbond.economic.systems.market.IMoneyAccount;
import jeconbond.economic.systems.market.ISellProposition;
import jeconbond.economic.systems.market.MoneyAccount;
import jeconbond.economic.resources.*;

import java.util.Collection;
import java.util.List;
import java.util.ArrayList;

public class AntAgent extends BaseEconProdDecoratod implements IProcessDealStrategy {
	private static final ResourceStorrage EMPTY_OUTPUT_RS = new ResourceStorrage();

	private static final double INF_MONEY = 1e10;
	private static final IResourceType FAKE_TYPE = new ResourceType("FAKE_TYPE");
	
	private IMarketResourceRedestributionSystem mrrs;
	private IMoneyAccount money = new MoneyAccount();
	
	private IFeramonStorrage feramonStorrage;
	private IWalkStrategy walkStrategy;

	private List<IOutcome> outcomesHistory = new ArrayList<IOutcome>();
	private double infMoney = INF_MONEY;
	private ObserveCostsProfitMerchantDecorator observeCPtMerch;

	public AntAgent(INode root, IFeramonStorrage feramonStorrage) {
		super(new AutomataAgent(root));
		this.feramonStorrage = feramonStorrage;
	}

	public void setWalkStrategy(IWalkStrategy walkStrategy) {
		this.walkStrategy = walkStrategy;
	}

	public void setFeramonStorrage(IFeramonStorrage feramonStorrage) {
		this.feramonStorrage = feramonStorrage;
	}

	public void setRNInformer(
			IResourceNecessityInformer informer, 
			IMarketResourceRedestributionSystem mrrs
	) {
		ProductNecessityMerchant pnMerchant = new ProductNecessityMerchant(
				mrrs,
				money,
				subagent.getInputRS(),
				EMPTY_OUTPUT_RS,
				informer,
				1.0
		);
		observeCPtMerch = new ObserveCostsProfitMerchantDecorator(
				pnMerchant,
				money,
				1,
				EMPTY_OUTPUT_RS
		);
		observeCPtMerch.setProcessDealStrategy(this);
		this.mrrs = mrrs;
		subagent.setMerchant(observeCPtMerch);
	}
	
	@Override
	public void processDeal(ISellProposition sellProposition, double value) {
		double totalPrice = sellProposition.getPrice() * value;
		money.changeBalance(-totalPrice);
		subagent.getInputRS().storeResource(sellProposition.getType(), value);
	}
	
	static { System.out.println("\nBLOCKING what a fucking: ); // real value and type 8-) of produced not matter."); }

	@Override
	public void processPreProduceStage() {
		double lastProfit = computeLastProfit();
		if (lastProfit > 0) {
			writeProfitFeramon(lastProfit);
			subagent.getOutputRS().clear();
			observeCPtMerch.writeProduced(
					lastProfit,
					FAKE_TYPE
			); // real value and type 8-) of produced not matter. 
		}
		money.changeBalance(infMoney - money.getBalance());
		subagent.processPreProduceStage();
	}

	@Override
	public void processProduceStage() {
		AutomataAgent automataAgent = (AutomataAgent) subagent;
		IOutcome out = walkStrategy.doWalk(automataAgent.getState());
		if (out != null) {
			automataAgent.setState(out.getDestination());
			outcomesHistory.add(out);
		}
	}

	@Override
	public void processPostProduceStage() {
		subagent.processPostProduceStage();
	}
	
	private void writeProfitFeramon(double profit) {
		for (IOutcome out : outcomesHistory) {
			feramonStorrage.storeFeramon(out, profit);
		}
		outcomesHistory.clear();
	}

	private double computeLastProfit() {
		double totalProfit = 0.0;
		Collection<ResourceBasket> produced = subagent.getOutputRS().listBaskets();
		for (ResourceBasket rb : produced) {
			if (rb.value > 0.0) {
				double marketPrice = ResourceUtils.avaluateMarketPrice(rb.type, mrrs);
				double profit = marketPrice * rb.value;
				profit -= observeCPtMerch.getLastCost();
				totalProfit += profit;
			}
		}
		return totalProfit;
	}
}
